(function(){
	var EDITABLE = ["TEXTAREA", "INPUT"];
	/*
	    Function: isEditable
	    
	    return true if the the tag name is a editable element
	*/
	function isEditable(text){
		if (text == null || text.toUpperCase == null){
			return false;
		}
		var i = EDITABLE.length;
		while(i--){
			if (text.toUpperCase() == EDITABLE[i]){
				return true;
			}
		}
		return false;
	};
	
	/*
		Ctor: translator.selection
		x-browser implementation of w3 selection
	*/
	translator.selection = function(selection){
		this._selection = selection;
	};
	var sp = translator.selection.prototype;
	sp.getRangeAt = function(){
		var ret = null;
		if (this._selection.getRangeAt)
			ret = this._selection.getRangeAt.apply(this._selection, arguments);
		else if (this._selection.createRange){
			ret = this._selection.createRange();
		}
		return translator.range.wrap(ret);
	};
	sp.toString = function(){
		if (this._selection.getRangeAt && this._selection.toString){
			return this._selection.toString();
		}
		// ie
		return this.getRangeAt().toString();
	};
	translator.selection.wrap = function(selection){
		return new translator.selection(selection);
	};
	
	/*
		Ctor: translator.selection
		x-browser implementation of w3 range
	*/
	translator.range = function(range){
		this._range = range;
		
		this.text = mapo.prop(null, this._setText, this._getText);
	};
	var p = translator.range.prototype;
	p._setText = function(value){
		// ie
		if (this._range.text != null)
			this._range.text = value;
		else{
			this._range.deleteContents();
			this._range.insertNode(document.createTextNode(value));
		}
	};
	p._getText = function(){
		// ie
		if (this._range.text != null)
			return this._range.text;
		return this._range.toString();
	};
	p.startOffset = function(){
		if (this._range.startOffset)
			return this._range.startOffset;
		return null;
	};
	p.endOffset = function(){
		if (this._range.startOffset)
			return this._range.endOffset;
		return null;
	};
	p.commonAncestorContainer = function(){
		var ret = null;
		if (this._range.commonAncestorContainer){
			ret = this._range.commonAncestorContainer;
		}
		// ie
		else if (this._range.parentElement){
			ret = this._range.parentElement();
		}
		return ret;
	};
	p.deleteContents = function(){
		if (this._range.deleteContents){
			this._range.deleteContents.apply(this._range, arguments);
		}
		else if (this._range.text != null){
			// ie
			var p = this._range.parentElement();
			if (p !=null && isEditable(p.tagName)){
				
				p.value = "";
			}
			else{
				this._range.text = "";
			}
		}
	};
	p.insertNode = function(newNode){
		if (this._range.insertNode){
			this._range.insertNode.apply(this._range, arguments);
		}
		else if(this._range.parentElement){
		    var wrap = document.createElement("div");
		    wrap.innerHTML = this._range.htmlText;
		    wrap.appendChild(newNode);
			this._range.pasteHTML(wrap.innerHTML);
		}
	};
	p.toString = function(){
		return this.text();
	};
	translator.range.wrap  = function(range){
		return new translator.range(range);
	};
	
})();